﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ActivityActioner.cs" company="DissingNelleman">
//   
// All rights reserved. </copyright>
// <summary>
//   The activity actioner.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace ServiceLibrary.Actioners.Activities
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    using NHibernate;
    using NHibernate.Criterion;

    using ServiceLibrary.Models.Base;
    using ServiceLibrary.Models.Domain;
    using ServiceLibrary.Services.Commands;
    using ServiceLibrary.Services.Queries;
    using ServiceLibrary.Services.Results;

    using BusinessDevelopmentActivity = ServiceLibrary.Services.Dto.BusinessDevelopmentActivity;
    using NetworkingActivity = ServiceLibrary.Services.Dto.NetworkingActivity;

    /// <summary>
    /// The activity actioner.
    /// </summary>
    public class ActivityActioner : ActionerBase
    {
        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ActivityActioner"/> class.
        /// </summary>
        /// <param name="session">
        /// The session.
        /// </param>
        /// <param name="activeUser">
        /// The active user.
        /// </param>
        public ActivityActioner(ISession session, User activeUser)
            : base(session, activeUser)
        {
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The create activity.
        /// </summary>
        /// <param name="act">
        /// The act.
        /// </param>
        public void CreateActivity(Activity act)
        {
            if (act.BDA != null)
            {
                if (act.BDA.ID != Guid.Empty)
                {
                    var bda = this.Session.Get<Models.Domain.BusinessDevelopmentActivity>(act.BDA.ID);
                    if (bda == null)
                    {
                        bda = act.BDA;
                        bda.CreatedDateTime = DateTime.Now;
                        this.Session.Save(bda);
                    }

                    act.BDA = bda;
                }
            }

            if (act.NA != null)
            {
                if (act.NA.ID != Guid.Empty)
                {
                    var na = this.Session.Get<Models.Domain.NetworkingActivity>(act.NA.ID);
                    if (na == null)
                    {
                        na = act.NA;
                        na.CreatedDateTime = DateTime.Now;
                        this.Session.Save(na);
                    }

                    act.NA = na;
                }
            }

            act.CreatedDateTime = DateTime.Now;
            this.Session.Save(act);
            if (act.BDA != null)
            {
                this.Log.CreateLogEntry(
                    act.ID,
                    string.Format("Forretningsudviklingen beliggende '{0}' blev oprettet.", (act.TimeOfActivity.HasValue ?  act.TimeOfActivity.Value.ToShortDateString() : "")),
                    Enums.LogEntryType.BDA);
            }
            else
            {
                this.Log.CreateLogEntry(
                    act.ID,
                    string.Format("Netværksmødet beliggende '{0}' blev oprettet.", (act.TimeOfActivity.HasValue ?  act.TimeOfActivity.Value.ToShortDateString() : "")),
                    Enums.LogEntryType.NA);
            }
        }

        /// <summary>
        /// The create activity.
        /// </summary>
        /// <param name="cmd">
        /// The cmd.
        /// </param>
        public void CreateActivity(CreateActivityCommand cmd)
        {
            if (cmd != null)
            {
                if (cmd.Dto != null)
                {
                    var ac = new Activity
                                 {
                                     ID = cmd.Dto.ID,
                                     Commentary = cmd.Dto.Commentary,
                                     TimeOfActivity = cmd.Dto.TimeOfActivity,
                                     CreatedDateTime = DateTime.Now
                                 };

                    if (cmd.Dto.OwnerProjects != null && cmd.Dto.OwnerProjects.Any())
                    {
                        ac.OwnerProjects.Clear();
                        foreach (var project in cmd.Dto.OwnerProjects.Select(prID => this.Session.Get<Project>(prID)).Where(project => project != null))
                        {
                            ac.OwnerProjects.Add(project);
                        }
                    }

                    if (cmd.Dto.Attendees != null)
                    {
                        foreach (Guid id in cmd.Dto.Attendees)
                        {
                            var prof = this.Session.Get<Profile>(id);
                            if (prof != null)
                            {
                                ac.Attendees.Add(prof);
                            }
                        }
                    }

                    if (cmd.Dto.Location != null)
                    {
                        var loc = this.Session.Get<Location>(cmd.Dto.Location);
                        if (loc != null)
                        {
                            ac.Location = loc;
                        }
                    }

                    var cr = this.Session.Get<User>(cmd.Dto.Creator);
                    if (cr != null)
                    {
                        ac.Creator = cr;
                    }

                    if (cmd.Dto.NA != null)
                    {
                        this.CreateNetworkingActivity(cmd.Dto.NA);
                        var na = this.Session.Get<Models.Domain.NetworkingActivity>(cmd.Dto.NA.ID);

                        if (na != null)
                        {
                            ac.NA = na;
                        }
                    }

                    if (cmd.Dto.BDA != null)
                    {
                        this.CreateBusinessDevelopmentActivity(cmd.Dto.BDA);
                        var bda = this.Session.Get<Models.Domain.BusinessDevelopmentActivity>(cmd.Dto.BDA.ID);

                        if (bda != null)
                        {
                            ac.BDA = bda;
                        }
                    }

                    CreateActivity(ac);
                }
            }
        }

        /// <summary>
        /// The execute search query.
        /// </summary>
        /// <param name="query">
        /// The query.
        /// </param>
        /// <returns>
        /// The <see cref="ActivityResult"/>.
        /// </returns>
        public ActivityResult ExecuteSearchQuery(ActivityQuery query)
        {
            SearchSettings settings = query.Settings;

            var result = new ActivityResult();

            IQueryOver<Activity, Activity> search = this.Session.QueryOver<Activity>();
            this.ApplyDefaultCriterias(settings, search);

            if (query.HasBusinessDevelopment)
            {
                search = search.Where(x => x.BDA != null);

                if ((query.BAContainsTopics ?? new List<Guid>()).Any())
                {
                    var bdaSearch = this.Session.QueryOver<Models.Domain.BusinessDevelopmentActivity>();
                    bdaSearch.RootCriteria.CreateAlias("Topics", "top")
                             .Add(Restrictions.In("top.ID", query.BAContainsTopics));
                    var bdAs = bdaSearch.List();
                    if (bdAs.Any())
                    {
                        search.RootCriteria.CreateAlias("BDA", "bda")
                              .Add(Restrictions.In("bda.ID", bdAs.Select(x => x.ID).ToList()));
                    }
                }
            }

            if (query.HasNetworkActivity)
            {
                search = search.Where(x => x.NA != null);

                var searchNA = this.Session.QueryOver<Models.Domain.NetworkingActivity>();
                if (query.IsConferenceEvent.HasValue && query.IsConferenceEvent.Value)
                {
                    searchNA = searchNA.Where(x => x.IsConferenceEvent);
                }

                if (query.IsDelegationTravel.HasValue && query.IsDelegationTravel.Value)
                {
                    searchNA = searchNA.Where(x => x.IsDelegationTravel);
                }

                if (query.IsNetworkingEvent.HasValue && query.IsNetworkingEvent.Value)
                {
                    searchNA = searchNA.Where(x => x.IsNetworkingEvent);
                }

                if (query.IsProductLaunch.HasValue && query.IsProductLaunch.Value)
                {
                    searchNA = searchNA.Where(x => x.IsProductLaunch);
                }

                if (query.NABooth.HasValue && query.NABooth.Value)
                {
                    searchNA = searchNA.Where(x => x.Booth);
                }

                if (query.NAAttendance.HasValue && query.NAAttendance.Value)
                {
                    searchNA = searchNA.Where(x => x.Attendance);
                }

                if (query.NAOrganizer.HasValue && query.NAOrganizer.Value)
                {
                    searchNA = searchNA.Where(x => x.Organizer);
                }

                //if (query.WithOrganizer.HasValue && query.WithOrganizer.Value != Guid.Empty)
                //{
                //    searchNA = searchNA.Where(x => x.Organizer.ID == query.WithOrganizer.Value);
                //}

                if (query.WithSupportForBusinessAttendance != null && query.WithSupportForBusinessAttendance.Any())
                {
                    searchNA.RootCriteria.CreateAlias("SupportForBusinessAttendance", "sfba")
                             .Add(Restrictions.In("sfba.ID", query.WithSupportForBusinessAttendance));
                }

                if (query.WithPresentations != null && query.WithPresentations.Any())
                {
                    searchNA.RootCriteria.CreateAlias("Presentations", "prs")
                             .Add(Restrictions.In("prs.ID", query.WithPresentations));
                }

                var naList = searchNA.List();
                if (naList.Any())
                {
                    search.RootCriteria.CreateAlias("NA", "na")
                          .Add(Restrictions.In("na.ID", naList.Select(x => x.ID).ToList()));
                }

            }

            if (query.AtLocation.HasValue && query.AtLocation.Value != Guid.Empty)
            {
                search = search.Where(x => x.Location.ID == query.AtLocation.Value);
            }

            if (query.WithAttendees != null && query.WithAttendees.Any())
            {
                search.RootCriteria.CreateAlias("Attendees", "at")
                      .Add(Restrictions.In("at.ID", query.WithAttendees));
            }

            var profilesAreAtRemoteArea = query.ProfilesAreAtRemoteArea ?? false;
            var profilesAreEntrepreneur = query.ProfilesAreEntrepreneur ?? false;
            if (profilesAreAtRemoteArea || profilesAreEntrepreneur)
            {
                var searchProfiles = this.Session.QueryOver<Models.Domain.Profile>();

                if (profilesAreAtRemoteArea)
                {
                    searchProfiles = searchProfiles.Where(x => x.IsRemoteArea);
                }

                if (profilesAreEntrepreneur)
                {
                    searchProfiles = searchProfiles.Where(x => x.IsEntrepreneur);
                }

                var profileList = searchProfiles.List().Select(x => x.ID);

                if (profileList.Any())
                {
                    search.RootCriteria.CreateAlias("Attendees", "atprof")
                          .Add(Restrictions.In("atprof.ID", profileList.ToArray()));
                }
                else
                {
                    //No profiles match the search, force return 0 results
                    search = search.Where(x => x.ID == Guid.Empty);
                }
            }
            

            this.ApplyDefaultSearchFieldCriteriasReportsSearch(query.DefaultFields, search);

            result.TotalRowCount = search.RowCount();

            List<Activity> activities = this.Sort(settings, search.List()).ToList();

            this.ApplySkipAndTake(settings, activities);

            foreach (Activity act in activities)
            {
                Services.Dto.Activity dto = Services.Dto.Activity.Convert(act);
                if (dto != null)
                {
                    result.List.Add(dto);
                }
            }

            return result;
        }

        /// <summary>
        /// The get activity.
        /// </summary>
        /// <param name="id">
        /// The id.
        /// </param>
        /// <returns>
        /// The <see cref="Activity"/>.
        /// </returns>
        public Activity GetActivity(Guid id)
        {
            var what = this.Session.Get<Activity>(id);

            return what;
        }

        #endregion

        #region Methods

        /// <summary>
        /// The create activity related objects.
        /// </summary>
        internal void CreateActivityRelatedObjects()
        {
            IList<Presentation> presentations = this.Session.QueryOver<Presentation>().List();
            var pA = new PresentationActioner(this.Session, this.ActiveUser);
            var defaultPresentation = new List<string>
                                          {
                                              "WT", 
                                              "Fonde - Opi-pulje", 
                                              "Fonde - Markedsmodningsfond", 
                                              "Fonde - Regionalfond", 
                                              "Fonde - Socialfond", 
                                              "Fonde - Øvrige nationale fonde", 
                                              "Fonde - EU-fonde", 
                                              "Fonde - Øvrige internationale fonde", 
                                              "PATH - Platform", 
                                              "PATH - Nonplatform", 
                                              "Andet"
                                          };
            foreach (var newPresentation in from presentation in defaultPresentation let alreadyExists = (from p in presentations where p.Name.Equals(presentation) select p).Any() where !alreadyExists select new Presentation { ID = Guid.NewGuid(), Name = presentation })
            {
                pA.CreatePresentation(newPresentation);
            }
        }

        /// <summary>
        /// The delete activity.
        /// </summary>
        /// <param name="cmd">
        /// The cmd.
        /// </param>
        internal void DeleteActivity(DeleteActivityCommand cmd)
        {
            if (cmd != null && (cmd.Dto != null && !cmd.Dto.Equals(Guid.Empty)))
            {
                var act = this.Session.Get<Activity>(cmd.Dto);
                if (act != null)
                {
                    if (act.BDA != null)
                    {
                        this.Log.CreateLogEntry(
                            act.ID,
                            string.Format("Forretningsudviklingen beliggende '{0}' blev slettet.", (act.TimeOfActivity.HasValue ?  act.TimeOfActivity.Value.ToShortDateString() : "")),
                            Enums.LogEntryType.BDA,
                            Enums.LogEntryActionType.Delete);
                    }
                    else
                    {
                        this.Log.CreateLogEntry(
                            act.ID,
                            string.Format("Netværksmødet beliggende '{0}' blev slettet.", (act.TimeOfActivity.HasValue ?  act.TimeOfActivity.Value.ToShortDateString() : "")),
                            Enums.LogEntryType.NA,
                            Enums.LogEntryActionType.Delete);
                    }

                    if (act.NA != null)
                    {
                        this.Session.Delete(act.NA);
                        act.NA = null;
                    }

                    if (act.BDA != null)
                    {
                        this.Session.Delete(act.BDA);
                        act.BDA = null;
                    }

                    this.Session.Delete(act);
                }
            }
        }

        /// <summary>
        /// The create business development activity.
        /// </summary>
        /// <param name="theBda">
        /// The the bda.
        /// </param>
        private void CreateBusinessDevelopmentActivity(BusinessDevelopmentActivity theBda)
        {
            var bda = new Models.Domain.BusinessDevelopmentActivity
                          {
                              AdditionalComments = theBda.AdditionalComments,
                              ID = theBda.ID,
                              CreatedDateTime = DateTime.Now,
                              TopicElaboration = theBda.TopicElaboration
                          };
            if (theBda.Topics != null)
            {
                foreach (Guid id in theBda.Topics)
                {
                    var top = this.Session.Get<Topic>(id);
                    if (top != null)
                    {
                        bda.Topics.Add(top);
                    }
                }
            }

            this.Session.Save(bda);
        }

        /// <summary>
        /// The create networking activity.
        /// </summary>
        /// <param name="theNa">
        /// The the na.
        /// </param>
        private void CreateNetworkingActivity(NetworkingActivity theNa)
        {
            var na = new Models.Domain.NetworkingActivity
                         {
                             Booth = theNa.Booth ?? false,
                             Attendance = theNa.Attendance ?? false,
                             Organizer = theNa.Organizer ?? false,
                             CreatedDateTime = DateTime.Now,
                             ID = theNa.ID,
                             IsConferenceEvent = theNa.IsConferenceEvent ?? false,
                             IsDelegationTravel = theNa.IsDelegationTravel ?? false,
                             IsNetworkingEvent = theNa.IsNetworkingEvent ?? false,
                             IsProductLaunch = theNa.IsProductLaunch ?? false,
                             IsNational = theNa.IsNational ?? true
                         };
          

            if (theNa.Presentations != null)
            {
                foreach (Guid id in theNa.Presentations)
                {
                    var pres = this.Session.Get<Presentation>(id);
                    if (pres != null)
                    {
                        na.Presentations.Add(pres);
                    }
                }
            }

            na.ProductType = theNa.ProductType;
            if (theNa.SupportForBusinessAttendance != null)
            {
                foreach (Guid id in theNa.SupportForBusinessAttendance)
                {
                    var prof = this.Session.Get<Profile>(id);
                    if (prof != null)
                    {
                        na.SupportForBusinessAttendance.Add(prof);
                    }
                }
            }

            this.Session.Save(na);
        }

        /// <summary>
        /// The sort.
        /// </summary>
        /// <param name="settings">
        /// The settings.
        /// </param>
        /// <param name="search">
        /// The search.
        /// </param>
        /// <returns>
        /// The sorted list of activities.
        /// </returns>
        private IEnumerable<Activity> Sort(SearchSettings settings, IEnumerable<Activity> search)
        {
            bool asc = settings.SortAscending == null || (bool)settings.SortAscending;

            if (settings.OrderBy != null)
            {
                switch (settings.OrderBy)
                {
                    case "Location.Name":
                        return asc
                                   ? search.OrderBy(x => x.Location.Name)
                                   : search.OrderByDescending(x => x.Location.Name);
                    case "Creator.Name":
                        return asc ? search.OrderBy(x => x.Creator.Name) : search.OrderByDescending(x => x.Creator.Name);
                    case "Attendance":
                        return asc
                                   ? search.OrderBy(x => x.NA.Attendance)
                                   : search.OrderByDescending(x => x.NA.Attendance);
                    case "ProductType":
                        return asc
                                   ? search.OrderBy(x => x.NA.ProductType)
                                   : search.OrderByDescending(x => x.NA.ProductType);
                    
                    // Add more orderbys
                }
            }

            return asc ? search.OrderBy(x => x.TimeOfActivity) : search.OrderByDescending(x => x.TimeOfActivity);
        }

        /// <summary>
        /// The update activity.
        /// </summary>
        /// <param name="cmd">
        /// The cmd.
        /// </param>
        internal void UpdateActivity(UpdateActivityCommand cmd)
        {
            if (cmd.Dto != null)
            {
                var changedActivity = this.Session.Get<Activity>(cmd.Dto.ID);
                if (changedActivity != null)
                {
                    changedActivity.Commentary = cmd.Dto.Commentary;
                    changedActivity.TimeOfActivity = cmd.Dto.TimeOfActivity;

                    changedActivity.Attendees.Clear();
                    if (cmd.Dto.Attendees != null)
                    {
                        foreach (Guid id in cmd.Dto.Attendees)
                        {
                            var prof = this.Session.Get<Profile>(id);
                            if (prof != null)
                            {
                                changedActivity.Attendees.Add(prof);
                            }
                        }
                    }

                    if (cmd.Dto.OwnerProjects != null && cmd.Dto.OwnerProjects.Any())
                    {
                        changedActivity.OwnerProjects.Clear();
                        foreach (Guid prID in cmd.Dto.OwnerProjects)
                        {
                            var project = this.Session.Get<Project>(prID);
                            if (project != null)
                            {
                                changedActivity.OwnerProjects.Add(project);
                            }
                        }
                    }

                    var loc = this.Session.Get<Location>(cmd.Dto.Location);
                    changedActivity.Location = loc;

                    if (cmd.Dto.Creator != null)
                    {
                        var cr = this.Session.Get<User>(cmd.Dto.Creator);
                        if (cr != null)
                        {
                            changedActivity.Creator = cr;
                        }
                    }

                    if (cmd.Dto.NA != null)
                    {
                        if (changedActivity.NA == null)
                        {
                            changedActivity.NA = new Models.Domain.NetworkingActivity()
                            {
                                ID = Guid.NewGuid(),
                                CreatedDateTime = DateTime.Now
                            };
                        }
                        this.UpdateNetworkingActivity(changedActivity.NA, cmd.Dto.NA);
                    }
                    else
                    {
                        changedActivity.NA = null;
                    }

                    if (cmd.Dto.BDA != null)
                    {
                        this.UpdateBusinessDevelopment(cmd.Dto.BDA);
                    }
                    else
                    {
                        changedActivity.BDA = null;
                    }

                    this.Session.Update(changedActivity);
                    if (changedActivity.BDA != null)
                    {
                        this.Log.CreateLogEntry(
                            changedActivity.ID,
                            string.Format("Forretningsudviklingen beliggende '{0}' blev opdateret.", (changedActivity.TimeOfActivity.HasValue ? changedActivity.TimeOfActivity.Value.ToShortDateString() : "")),
                            Enums.LogEntryType.BDA,
                            Enums.LogEntryActionType.Update);
                    }
                    else
                    {
                        this.Log.CreateLogEntry(
                            changedActivity.ID,
                            string.Format("Netværksmødet beliggende '{0}' blev opdateret.", (changedActivity.TimeOfActivity.HasValue ? changedActivity.TimeOfActivity.Value.ToShortDateString() : "")),
                            Enums.LogEntryType.NA,
                            Enums.LogEntryActionType.Update);
                    }
                }
            }
        }

        /// <summary>
        /// The update business development.
        /// </summary>
        /// <param name="bda">
        /// The bda.
        /// </param>
        private void UpdateBusinessDevelopment(BusinessDevelopmentActivity bda)
        {
            if (bda == null)
            {
                return;
            }

            var changedBda = this.Session.Get<Models.Domain.BusinessDevelopmentActivity>(bda.ID);

            if (changedBda == null)
            {
                return;
            }

            changedBda.AdditionalComments = bda.AdditionalComments;
            changedBda.ID = bda.ID;
            changedBda.TopicElaboration = bda.TopicElaboration;

            changedBda.Topics.Clear();
            if (bda.Topics == null)
            {
                return;
            }

            foreach (var top in bda.Topics.Select(id => this.Session.Get<Topic>(id)).Where(top => top != null))
            {
                changedBda.Topics.Add(top);
            }
        }

        /// <summary>
        /// The update networking activity.
        /// </summary>
        /// <param name="changedNetworkingActivity">
        /// The changed Networking Activity.
        /// </param>
        /// <param name="na">
        /// The na.
        /// </param>
        private void UpdateNetworkingActivity(Models.Domain.NetworkingActivity changedNetworkingActivity, NetworkingActivity na)
        {
            if (na != null && changedNetworkingActivity != null)
            {
                changedNetworkingActivity.Booth = na.Booth ?? false;
                changedNetworkingActivity.Attendance = na.Attendance ?? false;
                changedNetworkingActivity.Organizer = na.Organizer ?? false;
                changedNetworkingActivity.ProductType = na.ProductType;
                changedNetworkingActivity.IsConferenceEvent = na.IsConferenceEvent ?? false;
                changedNetworkingActivity.IsDelegationTravel = na.IsDelegationTravel ?? false;
                changedNetworkingActivity.IsNetworkingEvent = na.IsNetworkingEvent ?? false;
                changedNetworkingActivity.IsProductLaunch = na.IsProductLaunch ?? false;
                changedNetworkingActivity.IsNational = na.IsNational ?? true;

                changedNetworkingActivity.Presentations.Clear();
                if (na.Presentations != null)
                {
                    foreach (Guid id in na.Presentations)
                    {
                        var pres = this.Session.Get<Presentation>(id);
                        if (pres != null)
                        {
                            changedNetworkingActivity.Presentations.Add(pres);
                        }
                    }
                }

                changedNetworkingActivity.SupportForBusinessAttendance.Clear();
                if (na.SupportForBusinessAttendance != null)
                {
                    foreach (Guid id in na.SupportForBusinessAttendance)
                    {
                        var prof = this.Session.Get<Profile>(id);
                        if (prof != null)
                        {
                            changedNetworkingActivity.SupportForBusinessAttendance.Add(prof);
                        }
                    }
                }

                //this.Session.Update(changedNetworkingActivity);

            }
        }

        #endregion
    }
}